package model;

import java.io.File;
import java.io.IOException;
import java.util.*;
import javax.imageio.ImageIO;
import controller.Controller;
import parser.Parser;
import resourceManager.ResourceManager;
import nodes.AbstractNode;
import nodes.VariableNode;



/**
 * The "command-center" class for the entire model. Each tab of the GUI has
 * exactly one unique model which contains exactly one pixmap.
 * 
 * @author Andrew Patterson
 */
public class Model
{
    private ResourceManager resources =  ResourceManager.getInstance();

    private List<Turtle> myTurtles; // All turtles that have been created
    private List<Turtle> myActiveTurtles; // The active turtles
    private HashMap<String, AbstractNode > myVariables;   // Maps variable names to their contents
    private Pixmap myPixmap;
    private Controller myController;
    
    //Other classes
    Parser myParser;
    
    /**
     * Creates a new model, an initial turtle, a variable map & parser
     */
    public Model (Controller controller)
    {
        resources.addResourcesFromFile("model");
        myController = controller;
        myPixmap = new Pixmap(this);
        changeBackground(resources.getString("default_background_file_name"));
        myTurtles = new ArrayList<Turtle>();
        myActiveTurtles = new ArrayList<Turtle>(); 
        myActiveTurtles.add(new Turtle(myPixmap, this)); // Create an initial turtle
        myTurtles.add(myActiveTurtles.get(0));       
        myVariables = new HashMap<String, AbstractNode>();
        myParser = new Parser(this);
        myController.updatePixmap(myPixmap);
    }
    

    /**
     * The main method of the model. It takes in a String input, uses a parser to
     * parse it, reads through the expression tree and executing the commands
     * 
     * @param input
     */
    public void processInput (String input)
    {
        List<AbstractNode> expressionTrees = null;
        try
        {
             expressionTrees = myParser.makeExpression(input);
        }
        catch (Exception e)
        { 
            resources.addResourcesFromFile("model");
        	myController.displayErrorMessage(resources.getString("input_error_message"));
        	return;
        }
        
        for(AbstractNode currentRootNode : expressionTrees)
        {
            AbstractNode result = currentRootNode.evaluate();
            
            // If result has output for the user
            if (result instanceof VariableNode)
            {
                myController.displayOutput(result.toString());
            }
        }
        myController.updatePixmap(myPixmap);
        
    }

    /**
     * Clears the screen, erases all turtles and places one new turtle at the starting location
     */
    public void clearscreen ()
    {        
        resources.addResourcesFromFile("model");
        myPixmap = new Pixmap(this);
        changeBackground(resources.getString("default_background_file_name"));
        myTurtles = new ArrayList<Turtle>();
        myActiveTurtles = new ArrayList<Turtle>(); 
        myActiveTurtles.add(new Turtle(myPixmap, this)); // Create an initial turtle
        myTurtles.add(myActiveTurtles.get(0));       
    }
    
    /**
     * Sets active turtles.  If a referenced turtle does not exist
     * a new one is made
     */
    public void setActiveTurtles(ArrayList<Integer> turtles)
    {
        myActiveTurtles.clear();
        for(int currentTurtle : turtles)
        {
            if(myTurtles.size() < currentTurtle)
            {
                Turtle newTurtle = new Turtle(myPixmap, this);
                myTurtles.add(newTurtle);
                myActiveTurtles.add(newTurtle);
            }
            else{
                myActiveTurtles.add(myTurtles.get(currentTurtle));
            }
        }
    }
    
    
    /**
     * Changes the background of the pixmap to an image
     * specified by a file path
     */
    public void changeBackground(String path)
    {
        try
        {
            myPixmap.setBackgroundImage(ImageIO.read(new File(path)));
        }
        catch (IOException e)
        {
            myController.displayErrorMessage(resources.getString("image_error_message"));
        }
    }
    
    
    /**
     * Puts a new variable in the map
     */
    public void putVariable(String variableName, AbstractNode value)
    {
        myVariables.put(variableName, value);
    }
    
    
    /**
     * Returns which turtle is currently active
     */
    public List<Turtle> getActiveTurtles ()
    {
        return myActiveTurtles;
    }
    
    
    /**
     * Returns a list of all created turtles
     */
    public List<Turtle> getAllTurtles ()
    {
        return myTurtles;
    }
  
    
    /**
     * Gets the variable map
     * 
     * @return the model's variable map
     */
    public Map<String, AbstractNode> getVariableMap()
    {
        return myVariables;
    }
    
    
    /**
     * Returns this model's pixmap
     */
    public Pixmap getPixmap()
    {
        return myPixmap;
    }

    /**
     * Returns this model's controller (Seldom used)
     */
	public Controller getController() {
		return myController;
	}
}
